package top.v5it.japi.plus.core.spring.web.interceptor;

import lombok.extern.slf4j.Slf4j;
import top.v5it.japi.plus.common.util.AssertData;
import top.v5it.japi.plus.core.ConstantPool;
import top.v5it.japi.plus.core.cache.JapiCache;
import top.v5it.japi.plus.core.exception.JapiAuthorizedException;
import top.v5it.japi.plus.core.exception.JapiSignatureException;
import top.v5it.japi.plus.core.spring.web.JapiHttpServletRequestWrapper;
import top.v5it.japi.plus.core.util.HttpServletUtil;
import top.v5it.japi.plus.core.util.JapiSecureUtil;
import top.v5it.japi.plus.log.OperLogService;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;

import static top.v5it.japi.plus.common.ConstantCommon.LOG_DIVIDING_LINE;

/**
 * SHA256-RSA2048授权
 *
 * @author zhanpu
 * @date 2022/6/8
 */
@Slf4j
public class JapiSha256SignatureAuthorizedInterceptor extends JapiAuthorizedInterceptor {

    /**
     * 构造函数注入
     *
     * @param redisTemplate  redis
     * @param operLogService 操作日志
     */
    public JapiSha256SignatureAuthorizedInterceptor(JapiCache japiCache, OperLogService operLogService, final long timeout, final long diffTime) {
        super(japiCache, operLogService, timeout, diffTime);
    }

    /**
     * 验证客户端请求上送的服务端证书序列号是否与服务端证书序列号一致
     *
     * @param request {@link HttpServletRequest}
     */
    @Override
    public void verifySerial(HttpServletRequest request) {

        String serverSerialNo = HttpServletUtil.getSerial(request);
        log.debug("{}{}\n{}{}", LOG_DIVIDING_LINE, ConstantPool.getHeadSerialName(), serverSerialNo, LOG_DIVIDING_LINE);

        Object objV = japiCache.getServerCertInfo("serialNo:" + serverSerialNo);
        AssertData.notBlankIfStr(objV, () -> new JapiAuthorizedException("请求头[{}]无效", ConstantPool.getHeadSerialName()));
    }

    /**
     * 验证签名值
     *
     * @param request
     * @param authMap
     */
    @Override
    public void verifySignature(HttpServletRequest request, Map<String, String> authMap) {

        String signature =
                AssertData.notBlank(authMap.get(ConstantPool.SIGNATURE_NAME)
                        , () -> new JapiAuthorizedException("签名值为空"));
        log.debug("{}请求签名值\n{}{}", LOG_DIVIDING_LINE, signature, LOG_DIVIDING_LINE);

        String serialNo =
                AssertData.notBlank(authMap.get(ConstantPool.SERIAL_NAME)
                        , () -> new JapiAuthorizedException("证书序列号为空"));
        log.debug("{}请求证书序列号\n{}{}", LOG_DIVIDING_LINE, serialNo, LOG_DIVIDING_LINE);

        String timestamp = authMap.get(ConstantPool.TIMESTAMP_NAME);
        String nonceStr = authMap.get(ConstantPool.NONCE_NAME);

        String body = request instanceof JapiHttpServletRequestWrapper ? ((JapiHttpServletRequestWrapper) request).getBody() : "";

        String message = buildMessage(request, timestamp, nonceStr, body);
        log.debug("{}构造签名串\n{}{}", LOG_DIVIDING_LINE, message, LOG_DIVIDING_LINE);

        boolean verify;

        try {
            verify = JapiSecureUtil.sha256Verify(signature, message, serialNo);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new JapiSignatureException("验证签名失败");
        }

        AssertData.isTrue(verify, () -> new JapiSignatureException("验证签名失败"));
    }
}
